import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;


public class Question3 extends Question1{

	
	public Question3(OutputGraphs graphs) {
		super(graphs);
	}
	public void run() throws IOException {
		EXAMPLES_FILE = "org.txt";
		ExamplesInputReader reader = new ExamplesInputReader();
		ArrayList<Example> allExmples = reader.getExamples(EXAMPLES_FILE);
		//creating the the power set of all the examples 2^n combinations
		Collection<ArrayList<Integer>> powerSet = getAllPowerSet();
		QuestionData data[]=new QuestionData[Constants.TOTAL_NUMBER_OF_DIGITS];
		for (int i = 1; i <= Constants.TOTAL_NUMBER_OF_DIGITS; i++) {
			//get all the groups from the size i:
			Collection<ArrayList<Example>> subset =getExamplesSubsetBySize(i,powerSet,allExmples);
			//running over all the groups
			data[i-1] =new QuestionData();
			for (ArrayList<Example> exampleSet : subset) {
				
				int numberThatLearned=checkNetwork(exampleSet);
				data[i-1].newNumber(numberThatLearned);
			}
			System.out.println(" i :"+i+" max: "+data[i-1].getMax()+ " avg= "+data[i-1].getAvg());
		}
		grapic.questionThree(data);
				
		
	}

	private Collection<ArrayList<Example>> getExamplesSubsetBySize(int i,
			Collection<ArrayList<Integer>> powerSet, ArrayList<Example> allExmples) {
		
		LinkedList<ArrayList<Example>> subsets = new LinkedList<ArrayList<Example>>();
		for (ArrayList<Integer> set : powerSet) {
			if (set.size()==i){
				ArrayList<Example> examples = new ArrayList<Example>();
				for (Integer integer : set) {
					for (Example ex : allExmples) {
						if (integer==ex.digit)
							examples.add(ex);			
					}
				}
				subsets.add(examples);
			}
				
				
		}
		return subsets;
	}
	protected int checkNetwork(ArrayList<Example> exampleSet) {
		//QuestionData data = new QuestionData();
		// new examples (SIZE_OF_CHANGED_EXAMPLES for each 1 example)
		Collection<Example> exampelsWithNoise = new LinkedList<Example>();
		//building the noise examples
		for (Example example : exampleSet) {
			for (int i = 0; i < Constants.SIZE_OF_CHANGED_EXAMPLES_Q3; i++) {
				exampelsWithNoise.add(getExampleWithChanges(example,example.digit));
				
			}
		}
		//learning set: the real examples:
		HopfieldNetwork hn = new HopfieldNetwork(exampleSet);
		int numberCorrect=0;
		int indexInExampleSet=0;
		int index=0;
		boolean test[]=new boolean[exampleSet.size()];
		for (Example example : exampelsWithNoise) {
			
			if (index==Constants.SIZE_OF_CHANGED_EXAMPLES_Q3*Constants.NUMBER_OF_DIGIT_EXAMPLE)
			{
				indexInExampleSet+=1;
				index=0;
				if(numberCorrect>=0.9*Constants.SIZE_OF_CHANGED_EXAMPLES_Q3)
					test[indexInExampleSet]=true;
				else
					test[indexInExampleSet]=false;
				
				numberCorrect=0;
			}
			
			Example returnEx=hn.reconstructExample(example);
			
			if(isExampleMatch(returnEx,exampleSet))
				numberCorrect++;
			index++;
		}
		
		if (index==Constants.SIZE_OF_CHANGED_EXAMPLES_Q3*Constants.NUMBER_OF_DIGIT_EXAMPLE)
		{
			indexInExampleSet+=1;
			index=0;
			if(numberCorrect>=0.9*(Constants.SIZE_OF_CHANGED_EXAMPLES_Q3*Constants.NUMBER_OF_DIGIT_EXAMPLE))
				test[indexInExampleSet-1]=true;
			else
				test[indexInExampleSet-1]=false;
			
			numberCorrect=0;
		}
		int counter=0;
		for(int i=0; i<test.length; i++)
			if(test[i]==true)
				counter++;
		return counter;
	}

	private boolean isExampleMatch(Example returnEx, ArrayList<Example> exampleSet) {
		for (Example example : exampleSet) {
			if (example.digit==returnEx.digit)
				if (example.compareTo(returnEx)==0)
					return true;
			
		}
		return false;
	}
	protected Collection<ArrayList<Example>> chooseExamplesSubsetBySize(int i,
			Collection<ArrayList<Example>> powerSet) {
		LinkedList<ArrayList<Example>> subsets = new LinkedList<ArrayList<Example>>();
		for (ArrayList<Example> set : powerSet) {
			if (set.size()==i)
				subsets.add(set);
		}
		return subsets;
	}

	protected Collection<ArrayList<Integer>> getAllPowerSet() {
		LinkedList<ArrayList<Integer>> subsets = new LinkedList<ArrayList<Integer>>();
		subsets.add(new ArrayList<Integer>());
		for (int i = 0; i < Constants.TOTAL_NUMBER_OF_DIGITS; i++) {
			LinkedList<ArrayList<Integer>> newSubsets = new LinkedList<ArrayList<Integer>>();
			for (ArrayList<Integer> arrayList : subsets) {
			
					newSubsets.add(arrayList);
				
				ArrayList<Integer> subset =(ArrayList<Integer>)arrayList.clone();
				subset.add(i);
				newSubsets.add(subset);
				
			}
			subsets= newSubsets;
		}

		return subsets;
	}



}
